package com.jykj.modbus.equipment.controller;

import com.jykj.modbus.equipment.entity.HttpResponse;
import com.jykj.modbus.equipment.entity.ReturnModBus;
import com.jykj.modbus.equipment.entity.guard.Equipment;
import com.jykj.modbus.equipment.entity.guard.EquipmentData;
import com.jykj.modbus.equipment.entity.guard.EquipmentMessage;
import com.jykj.modbus.equipment.service.*;
import com.jykj.modbus.exception.SendDataToSerialPortFailure;
import com.jykj.modbus.exception.SerialPortOutputStreamCloseFailure;
import com.jykj.modbus.utils.ByteUtils;
import com.jykj.modbus.utils.MathUtils;
import com.jykj.util.config.AppConfig;
import gnu.io.SerialPort;
import org.springframework.data.repository.query.Param;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;

@RestController
@RequestMapping("/testmodbus")
public class ModBusTest {

    @Resource(name= "equipmentService")
    public EquipmentService service;
    @Resource(name= "equipmentDataService")
    public EquipmentDataService equipmentDataService;

    public static String judgeStr;

    //批量将电表表号存入数据库
    @ResponseBody
    @GetMapping(value = "/addInstrument")
    public HttpResponse addInstrument(){
        ReturnModBus returnModBus = new ReturnModBus();
        String title = "";
        String data = "";
        try {
            Test test = new Test();
            //查询当前数据库全部电表
            Equipment equipment = new Equipment();
            equipment.setSensorType("10010");
            List<Equipment> equipmentList = this.service.selectEquipmentList(equipment);
            EquipmentMessage equipmentMessage = new EquipmentMessage();
            equipmentMessage.setSensorType("10010");
            equipmentMessage.setMessageType(209);
            List<EquipmentMessage> equipmentMessages = this.service.selectEquipmentMessage(equipmentMessage);
            if (equipmentMessages.size() > 0){
                equipmentMessage = equipmentMessages.get(0);
            }else {
                title = "类型匹配失败;";
            }
            for (Equipment equ : equipmentList){
                //开启串口
                returnModBus = test.openSerialPort1(null , "10010" , "209" , equ , equipmentMessage.getResultsDigits());
                System.out.println(title+"发送查询电表表号指令:");
                Thread.sleep(1000);
                data = equipmentMessage.getMessage();
                //发送指令
                SerialPortManager.sendToPort(returnModBus.getSerialport(), ByteUtils.hexStr2Byte(data));
                for (int e = 0 ; e<10 ; e++){
                    if (test.equipmentData.getResultsFrame().length() == 44){
                        //调用表号处理接口,将表号存入对应设备信息中.
                        Map<String , Object> mapData = test.dataProcessing(equipment.getSensorType(), "209", test.equipmentData.getResultsFrame());
                        String instrument = mapData.get("Instrument").toString();
                        equ.setInstrumentNum(instrument);
                        int i = this.service.updateEquipment(equ);
                    }
                    Thread.sleep(1000);
                }
                //关闭串口
                test.closeSerialPort(null);
            }
        } catch (SendDataToSerialPortFailure e) {
            e.printStackTrace();
        } catch (SerialPortOutputStreamCloseFailure e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return HttpResponse.success("批量修改表号成功!");
    }


    /**
     * 传感器开启串口发送数据并接收
     * @param qus 查询类型
     * @param serialPort 串口号
     * @param sensorType 设备类型
     * @return HttpResponse
     */
    @ResponseBody
    @GetMapping(value = "/openPort")
    public HttpResponse openPort(@Param("serialPort") String serialPort,@Param("qus") String qus , @Param("sensorType") String sensorType) {
        Map<String, Object> mapData = new HashMap<>();
        ReturnModBus returnModBus = new ReturnModBus();
        String title = "";
        String data = "";
        Test test = new Test();
        try {
            Equipment equipment = new Equipment();
            //传感器类型
            equipment.setSensorType(sensorType);
            //串口号
            equipment.setSerialPort(serialPort);
            List<Equipment> list = this.service.selectEquipmentList(equipment);
            if (list.size() > 0){
                equipment = list.get(0);
            }else {
                return HttpResponse.fail("无法获取对应类型传感器",null);
            }
            //通过设备信息查询指令代码
            EquipmentMessage eqm = new EquipmentMessage();
            //设备类型
            eqm.setSensorType(sensorType);
            //查询类型
            eqm.setMessageType(Integer.parseInt(qus));
            List<EquipmentMessage> messages = this.service.selectEquipmentMessage(eqm);
            if (messages.size()>0){
                eqm = messages.get(0);
                title = eqm.getMessageNode();
            }else {
                title = "类型匹配失败;";
            }
            //开启串口
            returnModBus = test.openSerialPort1(null , sensorType , qus, equipment , eqm.getResultsDigits());
            //如果查询设备类型为电表传感器,需要先发送查询表号指令获取电表表号
            if (sensorType.equals(AppConfig.getProperty("sensor.electricity"))){
                String dataStr = equipment.getInstrumentNum();
                //计算校验符结果
                String jiaoStr = MathUtils.makeCheckSum("68" + dataStr + eqm.getMessage());
                //拼装指令
                data= "FEFEFEFE68"+dataStr+eqm.getMessage()+jiaoStr+"16";
            }else {
                data = eqm.getMessage();
            }
            Thread.sleep(1000);
            //发送指令
            byte[] aByte = ByteUtils.hexStr2Byte(data);
            System.out.println("发送指令:"+data);
            SerialPortManager.sendToPort(returnModBus.getSerialport(), aByte);
            for (int e = 0 ; e<10 ; e++){
                for (int t= 0 ; t<100;t++){
                    byte[] fromPort = SerialPortManager.readFromPort(returnModBus.getSerialport());
                    if ( fromPort.length > 0){
                        judgeStr = ByteUtils.byteArrayToHexString(fromPort , true);
                        EquipmentData equipmentData = test.dataProcessingByEle(judgeStr);
                        if (equipmentData.getJudgeNum() !=null && equipmentData.getJudgeNum() == 1){
                            System.out.println(":"+ judgeStr);
                            mapData = test.dataProcessing(sensorType, qus, equipmentData.getResultsFrame());
                            System.out.println("解析完成的串口数据:");
                            System.out.println(mapData);
                            //关闭串口直接读取串口获取到的串口数据
                            test.closeSerialPort(null);
                            judgeStr = "";
                            return HttpResponse.success(title+"查询成功!",mapData);
                        }
                    }
                    Thread.sleep(10);
                }
                if (test.equipmentData.getResultsFrame().length() > 0){
                    mapData = test.dataProcessing(sensorType, qus, test.equipmentData.getResultsFrame());
                    System.out.println("解析完成的串口数据:");
                    System.out.println(mapData);
                    //关闭串口
                    test.closeSerialPort(null);
                    judgeStr = "";
                    return HttpResponse.success(title+"查询成功!",mapData);
                }
                Thread.sleep(1000);
            }
            //关闭串口
            test.closeSerialPort(null);
            judgeStr = "";
        } catch (SendDataToSerialPortFailure e) {
            e.printStackTrace();
            //关闭串口
            test.closeSerialPort(null);
            judgeStr = "";
        } catch (SerialPortOutputStreamCloseFailure e) {
            e.printStackTrace();
            //关闭串口
            test.closeSerialPort(null);
            judgeStr = "";
        } catch (InterruptedException e) {
            e.printStackTrace();
            //关闭串口
            test.closeSerialPort(null);
            judgeStr = "";
        }
        return HttpResponse.fail(title+"查询失败,传感器响应超时!");
    }

    /**
     * 开启串口发送数据并接收,接收到的数据根据对应协议进行解析
     * @param qus 查询类型
     * @param serialPort 串口号
     * @param sensorType 设备类型
     * @return HttpResponse
     */
    @ResponseBody
    @GetMapping(value = "/sendDataAndReceiving")
    public HttpResponse sendDataAndReceiving(@Param("serialPort") String serialPort,@Param("qus") String qus , @Param("sensorType") String sensorType){
        String title = "";
        String data = "";
        Map<String, Object> mapData = new HashMap<>();
        Test test = new Test();
        JserialComm jserialComm = new JserialComm();
        try {
            Equipment equipment = new Equipment();
            //传感器类型
            equipment.setSensorType(sensorType);
            //串口号
            equipment.setSerialPort(serialPort);
            List<Equipment> list = this.service.selectEquipmentList(equipment);
            if (list.size() > 0){
                equipment = list.get(0);
            }else {
                return HttpResponse.fail("无法获取对应类型传感器",null);
            }
            //通过设备信息查询指令代码
            EquipmentMessage eqm = new EquipmentMessage();
            //设备类型
            eqm.setSensorType(sensorType);
            //查询类型
            eqm.setMessageType(Integer.parseInt(qus));
            List<EquipmentMessage> messages = this.service.selectEquipmentMessage(eqm);
            if (messages.size()>0){
                eqm = messages.get(0);
                title = eqm.getMessageNode();
            }else {
                title = "类型匹配失败;";
            }
            data = this.service.getMessageData(eqm, sensorType, equipment.getInstrumentNum());
            //开启串口
            jserialComm.connect(equipment);
            jserialComm.writeLine(data);
            ReturnModBus returnModBus = new ReturnModBus();
            returnModBus.setSensorType(sensorType);
            returnModBus.setType(qus);
            test.setReturnModBus(returnModBus);
            try{
                //读取数据
                judgeStr = jserialComm.readLine();
                if (judgeStr.length()>0){
                    EquipmentData equipmentData = new EquipmentData();
                    equipmentData.setResultsFrame(judgeStr);
                    equipmentData.setJudgeNum(1);
                    if (equipmentData.getJudgeNum() !=null && equipmentData.getJudgeNum() == 1){
                        System.out.println(":"+ judgeStr);
                        mapData = test.dataProcessing(sensorType, qus, equipmentData.getResultsFrame());
                        System.out.println("解析完成的串口数据:");
                        System.out.println(mapData);
                        //关闭串口直接读取串口获取到的串口数据
                        jserialComm.disconnect();
                        judgeStr = "";
                        return HttpResponse.success(title+"查询成功!",mapData);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                jserialComm.disconnect();
            }
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            jserialComm.disconnect();
        }
        return HttpResponse.fail(title+"查询失败,传感器响应超时!","");
    }

}
